package com.ctbri.JWLetter.frame;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.ctbri.JWLetter.util.PropUtil;

/**
 * Neo4j数据连接池
 * 
 * @author Hogan
 * 
 */
@Component
@Scope("singleton")
public class NeoDataPooledConnection {
	
	private Logger log = Logger.getLogger(getClass());

	/**
	 * 连接数据元实体
	 */
	private NeoDataBean neoDataBean;
	/**
	 * 记录创建的总的连接数
	 */
	private int contActive;
	/**
	 * 空闲连接队列
	 */
	private List<Connection> freeConnection = new Vector<Connection>();
	/**
	 * 活动连接队列
	 */
	private List<Connection> activeConnection = new Vector<Connection>();
	/**
	 * 将线程和连接绑定，保证事务能统一执行
	 */
	private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
	
	/**
	 * 初始化  
	 */
    public void init() { 
    	this.neoDataBean = loadNeoDataBean();
    	for (int i = 0; i < neoDataBean.getInitConnections(); i++) {  
    		Connection conn = newConnection();
            // 初始化最小连接数  
            if (conn != null) {  
                freeConnection.add(conn);  
                contActive++;  
            }  
        }  
    	log.info("初始化Neo4J连接数为："+ contActive);
    }  
    
    /**
     * 获取当前连接
     * @return
     */
    public Connection getCurrentConnecton(){  
        // 默认线程里面取  
    	Connection conn = threadLocal.get();  
        if(conn == null){  
            conn = getConnection();  
        }  
        return conn;  
    }
    
    /**
     * 获得连接 
     * @return
     */
    public synchronized Connection getConnection() {  
    	Connection conn = null;  
        try {  
            // 判断是否超过最大连接数限制  
            if(contActive < neoDataBean.getMaxActiveConnections()){  
                if (freeConnection.size() > 0) {  
                    conn = freeConnection.get(0);  
                    if (conn != null) {  
                        threadLocal.set(conn);  
                    }  
                    freeConnection.remove(0);  
                } else {  
                    conn = newConnection();  
                }  
			} else { 
                // 继续获得连接,直到从新获得连接  
                wait(this.neoDataBean.getConnTimeOut());  
                conn = getConnection();  
            }  
            if (conn != null) {  
                activeConnection.add(conn);  
                contActive ++;  
            }  
        } catch (Exception e) {  
            log.error("获取连接失败!",e);
            conn = null;
        } 
        return conn;  
    }  
    
    /**
     * 获得新连接  
     * @return
     */
	private synchronized Connection newConnection() {
		Connection connection = null;
		try {
			Class.forName(neoDataBean.getDriverClassName());
			connection = DriverManager.getConnection(
	                neoDataBean.getUrl(), neoDataBean.getUsername(), neoDataBean.getPassword());
		} catch (Exception e) {
			log.error("获取连接失败!",e);
			connection = null;
		}
		return connection;
	}

	/**
	 * 释放连接  
	 * @param conn
	 */
    public synchronized void releaseConn(Connection conn)  {  
        if (conn != null && freeConnection.size() <= neoDataBean.getMaxConnections()) {  
            freeConnection.add(conn);  
            activeConnection.remove(conn);  
            contActive --;  
            threadLocal.remove();  
            // 唤醒所有正待等待的线程，去抢连接  
            notifyAll();  
        }  
    } 
    
   /**
    * 销毁连接池  
    */
	public synchronized void destroy() {
		try {
			for (Connection conn : freeConnection) {
				if (conn != null) {
					conn.close();
				}
			}
			for (Connection conn : activeConnection) {
				if (conn != null) {
					conn.close();
				}
			}
			contActive = 0;
		} catch (SQLException e) {
			log.error("关闭Neo4j数据连接失败!",e);
		}
	}
	
	/**
	 * 加载ES连接对象
	 * @return
	 */
	public NeoDataBean loadNeoDataBean(){
		NeoDataBean neoDataBean= new NeoDataBean();
		neoDataBean.setUsername(PropUtil.getValue("neo4j.username"));
		neoDataBean.setPassword(PropUtil.getValue("neo4j.password"));
		neoDataBean.setUrl(PropUtil.getValue("neo4j.url"));
		neoDataBean.setDriverClassName(PropUtil.getValue("neo4j.driverClassName"));
		neoDataBean.setMinConnections(Integer.valueOf(PropUtil.getValue("neo4j.minConnections")));
		neoDataBean.setMaxConnections(Integer.valueOf(PropUtil.getValue("neo4j.maxConnections")));
		neoDataBean.setInitConnections(Integer.valueOf(PropUtil.getValue("neo4j.initConnections")));
		neoDataBean.setConnTimeOut(Long.valueOf(PropUtil.getValue("neo4j.connTimeOut")));
		neoDataBean.setMaxActiveConnections(Integer.valueOf(PropUtil.getValue("neo4j.maxActiveConnections")));
		neoDataBean.setConnectionTimeOut(Integer.valueOf(PropUtil.getValue("neo4j.connectionTimeOut")));
		return neoDataBean;
	}
	
	/**
	 * 连接数据元实体
	 * 
	 * @author Hogan
	 * 
	 */
	public static class NeoDataBean {
		
		/**
		 * Url
		 */
		private String url;
		/**
		 * 用户名
		 */
		private String username;
		/**
		 * 密码
		 */
		private String password;
		/**
		 * driverClass的全类名
		 */
		private String driverClassName;
		/**
		 * 最小连接数
		 */
		private int minConnections;
		/**
		 * 最大连接数
		 */
		private int maxConnections;
		/**
		 * 初始化连接数
		 */
		private int initConnections;
		/**
		 * 重复获得连接的频率
		 */
		private long connTimeOut;
		/**
		 * 最大允许的连接数，和数据库对应
		 */
		private int maxActiveConnections;
		/**
		 * 连接超时时间
		 */
		private long connectionTimeOut;
		public String getUrl() {
			return url;
		}
		
		public void setUrl(String url) {
			this.url = url;
		}
		
		public String getUsername() {
			return username;
		}
		
		public void setUsername(String username) {
			this.username = username;
		}
		
		public String getPassword() {
			return password;
		}
		
		public void setPassword(String password) {
			this.password = password;
		}
		
		public int getMinConnections() {
			return minConnections;
		}
		
		public void setMinConnections(int minConnections) {
			this.minConnections = minConnections;
		}
		
		public int getMaxConnections() {
			return maxConnections;
		}
		
		public void setMaxConnections(int maxConnections) {
			this.maxConnections = maxConnections;
		}
		
		public int getInitConnections() {
			return initConnections;
		}
		
		public void setInitConnections(int initConnections) {
			this.initConnections = initConnections;
		}
		
		public long getConnTimeOut() {
			return connTimeOut;
		}
		
		public void setConnTimeOut(long connTimeOut) {
			this.connTimeOut = connTimeOut;
		}
		
		public int getMaxActiveConnections() {
			return maxActiveConnections;
		}
		
		public void setMaxActiveConnections(int maxActiveConnections) {
			this.maxActiveConnections = maxActiveConnections;
		}
		
		public long getConnectionTimeOut() {
			return connectionTimeOut;
		}
		
		public void setConnectionTimeOut(long connectionTimeOut) {
			this.connectionTimeOut = connectionTimeOut;
		}

		public String getDriverClassName() {
			return driverClassName;
		}

		public void setDriverClassName(String driverClassName) {
			this.driverClassName = driverClassName;
		}
		
	}

}
